<!doctype html>
<html lang="zh-CN" data-theme="light">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width,initial-scale=1" />
    <meta name="generator" content="VuePress 2.0.0-beta.68" />
    <meta name="theme" content="VuePress Theme Hope 2.0.0-beta.250" />
    <style>
      html {
        background: #fff;
      }

      html[data-theme="dark"] {
        background: #1d1e1f;
      }

      body {
        background: var(--bg-color);
      }
    </style>
    <script>
      const userMode = localStorage.getItem("vuepress-theme-hope-scheme");
      const systemDarkMode =
        window.matchMedia &&
        window.matchMedia("(prefers-color-scheme: dark)").matches;

      if (userMode === "dark" || (userMode !== "light" && systemDarkMode)) {
        document.documentElement.setAttribute("data-theme", "dark");
      }
    </script>
    <meta name="referrer" content="no-referrer"><link rel="icon" href="https://gitee.com/eddie-lucas/images/raw/master/img/logo.jpg"><link rel="icon" href="https://gitee.com/eddie-lucas/images/raw/master/img/logo.png" type="image/png" sizes="512x512"><link rel="icon" href="https://gitee.com/eddie-lucas/images/raw/master/img/logo.png" type="image/png" sizes="192x192"><link rel="manifest" href="/manifest.webmanifest" crossorigin="use-credentials"><meta name="theme-color" content="#46bd87"><link rel="apple-touch-icon" href="https://gitee.com/eddie-lucas/images/raw/master/img/logo.png"><meta name="apple-mobile-web-app-capable" content="yes"><meta name="apple-mobile-web-app-status-bar-style" content="black"><meta name="msapplication-TileImage" content="https://gitee.com/eddie-lucas/images/raw/master/img/logo.png"><meta name="msapplication-TileColor" content="#ffffff"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover"><title>Spring4.3.x源码阅读 | 小刘Learning</title><meta name="description" content="">
    <link rel="preload" href="/assets/style-3ede7958.css" as="style"><link rel="stylesheet" href="/assets/style-3ede7958.css">
    <link rel="modulepreload" href="/assets/app-d83e1369.js"><link rel="modulepreload" href="/assets/Spring4.3.x源码阅读.html-ce67a2f8.js"><link rel="modulepreload" href="/assets/Spring4.3.x源码阅读.html-3475e320.js"><link rel="modulepreload" href="/assets/plugin-vue_export-helper-c27b6911.js">
    <link rel="prefetch" href="/assets/aboutMe.html-72f014c7.js" as="script"><link rel="prefetch" href="/assets/index.html-69cd5f22.js" as="script"><link rel="prefetch" href="/assets/Java集合.html-f6d1e995.js" as="script"><link rel="prefetch" href="/assets/MyBatis常见问题.html-3782c8f7.js" as="script"><link rel="prefetch" href="/assets/InnoDB的Buffer Pool.html-f0ae2755.js" as="script"><link rel="prefetch" href="/assets/InnoDB的行格式和页结构.html-31890643.js" as="script"><link rel="prefetch" href="/assets/MySQL中的各种锁.html-b819061d.js" as="script"><link rel="prefetch" href="/assets/MySQL中的排序.html-5442bdf2.js" as="script"><link rel="prefetch" href="/assets/MySQL事务与MVCC.html-11dea9ac.js" as="script"><link rel="prefetch" href="/assets/MySQL优化器原理.html-44cdf1f3.js" as="script"><link rel="prefetch" href="/assets/5种IO模型.html-623f6d24.js" as="script"><link rel="prefetch" href="/assets/Netty的线程模型.html-1933240c.js" as="script"><link rel="prefetch" href="/assets/粘包拆包问题.html-e5c58280.js" as="script"><link rel="prefetch" href="/assets/AOF和RDB持久化.html-de83ad53.js" as="script"><link rel="prefetch" href="/assets/Gossip协议.html-9cc1d704.js" as="script"><link rel="prefetch" href="/assets/Redisson看门狗机制.html-8e4e6651.js" as="script"><link rel="prefetch" href="/assets/主从复制原理.html-5692886d.js" as="script"><link rel="prefetch" href="/assets/内存淘汰策略.html-2108cb44.js" as="script"><link rel="prefetch" href="/assets/缓存击穿、穿透、雪崩.html-d043509c.js" as="script"><link rel="prefetch" href="/assets/过期键的删除策略.html-86aae1a3.js" as="script"><link rel="prefetch" href="/assets/NameServer.html-6a201ec6.js" as="script"><link rel="prefetch" href="/assets/消息发送.html-4164a815.js" as="script"><link rel="prefetch" href="/assets/消息持久化.html-ad4aec32.js" as="script"><link rel="prefetch" href="/assets/过滤器和拦截器的区别.html-c5dbe180.js" as="script"><link rel="prefetch" href="/assets/MySQL安装.html-ce91cf4e.js" as="script"><link rel="prefetch" href="/assets/nvm_node安装.html-c02c4943.js" as="script"><link rel="prefetch" href="/assets/xxl-job源码阅读.html-4a3b4336.js" as="script"><link rel="prefetch" href="/assets/算法补充题.html-82552fdf.js" as="script"><link rel="prefetch" href="/assets/转换函数.html-4e846421.js" as="script"><link rel="prefetch" href="/assets/分布式事务.html-4015f1f4.js" as="script"><link rel="prefetch" href="/assets/深入理解Java虚拟机.html-f58d9b73.js" as="script"><link rel="prefetch" href="/assets/Redis开发与运维.html-8fbbb19d.js" as="script"><link rel="prefetch" href="/assets/Redis设计与实现.html-3d2f28fe.js" as="script"><link rel="prefetch" href="/assets/中级开发（5年内） .html-fe02712d.js" as="script"><link rel="prefetch" href="/assets/初级开发（3年内）.html-669c578d.js" as="script"><link rel="prefetch" href="/assets/高级开发（8年内）.html-8e45d1a0.js" as="script"><link rel="prefetch" href="/assets/apache poi导致的oom.html-ac4f4186.js" as="script"><link rel="prefetch" href="/assets/Spring启动及扫描流程.html-dca86884.js" as="script"><link rel="prefetch" href="/assets/404.html-81a48005.js" as="script"><link rel="prefetch" href="/assets/index.html-2b6ad090.js" as="script"><link rel="prefetch" href="/assets/index.html-30245415.js" as="script"><link rel="prefetch" href="/assets/index.html-c2c088b3.js" as="script"><link rel="prefetch" href="/assets/index.html-f512ec67.js" as="script"><link rel="prefetch" href="/assets/index.html-e1891597.js" as="script"><link rel="prefetch" href="/assets/index.html-b77929dc.js" as="script"><link rel="prefetch" href="/assets/index.html-3e3e3234.js" as="script"><link rel="prefetch" href="/assets/index.html-db16fd88.js" as="script"><link rel="prefetch" href="/assets/index.html-02e59ce2.js" as="script"><link rel="prefetch" href="/assets/index.html-55c7e4fd.js" as="script"><link rel="prefetch" href="/assets/index.html-3b089dfb.js" as="script"><link rel="prefetch" href="/assets/index.html-ac5b8d61.js" as="script"><link rel="prefetch" href="/assets/index.html-a2f3ea26.js" as="script"><link rel="prefetch" href="/assets/index.html-b57e51cb.js" as="script"><link rel="prefetch" href="/assets/index.html-0c321714.js" as="script"><link rel="prefetch" href="/assets/index.html-6266e407.js" as="script"><link rel="prefetch" href="/assets/index.html-00f53358.js" as="script"><link rel="prefetch" href="/assets/index.html-7b46e405.js" as="script"><link rel="prefetch" href="/assets/index.html-219b1b1f.js" as="script"><link rel="prefetch" href="/assets/index.html-ecf569c4.js" as="script"><link rel="prefetch" href="/assets/aboutMe.html-a5377517.js" as="script"><link rel="prefetch" href="/assets/index.html-df94614a.js" as="script"><link rel="prefetch" href="/assets/Java集合.html-25980358.js" as="script"><link rel="prefetch" href="/assets/MyBatis常见问题.html-13559d56.js" as="script"><link rel="prefetch" href="/assets/InnoDB的Buffer Pool.html-2608d2bb.js" as="script"><link rel="prefetch" href="/assets/InnoDB的行格式和页结构.html-b66829d8.js" as="script"><link rel="prefetch" href="/assets/MySQL中的各种锁.html-eda1f1e8.js" as="script"><link rel="prefetch" href="/assets/MySQL中的排序.html-155835e9.js" as="script"><link rel="prefetch" href="/assets/MySQL事务与MVCC.html-5203098d.js" as="script"><link rel="prefetch" href="/assets/MySQL优化器原理.html-580192b8.js" as="script"><link rel="prefetch" href="/assets/5种IO模型.html-e14d32e5.js" as="script"><link rel="prefetch" href="/assets/Netty的线程模型.html-79ec3f0d.js" as="script"><link rel="prefetch" href="/assets/粘包拆包问题.html-ad117100.js" as="script"><link rel="prefetch" href="/assets/AOF和RDB持久化.html-8f530297.js" as="script"><link rel="prefetch" href="/assets/Gossip协议.html-68ce5f80.js" as="script"><link rel="prefetch" href="/assets/Redisson看门狗机制.html-f806e761.js" as="script"><link rel="prefetch" href="/assets/主从复制原理.html-c35d3468.js" as="script"><link rel="prefetch" href="/assets/内存淘汰策略.html-58163b51.js" as="script"><link rel="prefetch" href="/assets/缓存击穿、穿透、雪崩.html-d8d78972.js" as="script"><link rel="prefetch" href="/assets/过期键的删除策略.html-b2be5f51.js" as="script"><link rel="prefetch" href="/assets/NameServer.html-6ada07a1.js" as="script"><link rel="prefetch" href="/assets/消息发送.html-08920331.js" as="script"><link rel="prefetch" href="/assets/消息持久化.html-32746c2c.js" as="script"><link rel="prefetch" href="/assets/过滤器和拦截器的区别.html-56c13477.js" as="script"><link rel="prefetch" href="/assets/MySQL安装.html-c7803a3a.js" as="script"><link rel="prefetch" href="/assets/nvm_node安装.html-736601b9.js" as="script"><link rel="prefetch" href="/assets/xxl-job源码阅读.html-2b98669d.js" as="script"><link rel="prefetch" href="/assets/算法补充题.html-37debf9d.js" as="script"><link rel="prefetch" href="/assets/转换函数.html-44dfb333.js" as="script"><link rel="prefetch" href="/assets/分布式事务.html-e6634dbe.js" as="script"><link rel="prefetch" href="/assets/深入理解Java虚拟机.html-3810cea1.js" as="script"><link rel="prefetch" href="/assets/Redis开发与运维.html-76744132.js" as="script"><link rel="prefetch" href="/assets/Redis设计与实现.html-eccc56a7.js" as="script"><link rel="prefetch" href="/assets/中级开发（5年内） .html-a2fc4d16.js" as="script"><link rel="prefetch" href="/assets/初级开发（3年内）.html-e48a4104.js" as="script"><link rel="prefetch" href="/assets/高级开发（8年内）.html-9138cbdd.js" as="script"><link rel="prefetch" href="/assets/apache poi导致的oom.html-b39dacda.js" as="script"><link rel="prefetch" href="/assets/Spring启动及扫描流程.html-0b604fff.js" as="script"><link rel="prefetch" href="/assets/404.html-742f0851.js" as="script"><link rel="prefetch" href="/assets/index.html-160c66d3.js" as="script"><link rel="prefetch" href="/assets/index.html-bb7b1e80.js" as="script"><link rel="prefetch" href="/assets/index.html-116fe317.js" as="script"><link rel="prefetch" href="/assets/index.html-17f24df8.js" as="script"><link rel="prefetch" href="/assets/index.html-3fe5d15e.js" as="script"><link rel="prefetch" href="/assets/index.html-c894bb5e.js" as="script"><link rel="prefetch" href="/assets/index.html-25b31507.js" as="script"><link rel="prefetch" href="/assets/index.html-8bb87106.js" as="script"><link rel="prefetch" href="/assets/index.html-255fc5d5.js" as="script"><link rel="prefetch" href="/assets/index.html-373a73ca.js" as="script"><link rel="prefetch" href="/assets/index.html-d539e1a9.js" as="script"><link rel="prefetch" href="/assets/index.html-1475787c.js" as="script"><link rel="prefetch" href="/assets/index.html-8073adbe.js" as="script"><link rel="prefetch" href="/assets/index.html-2ff9332c.js" as="script"><link rel="prefetch" href="/assets/index.html-f14ceb6a.js" as="script"><link rel="prefetch" href="/assets/index.html-54082429.js" as="script"><link rel="prefetch" href="/assets/index.html-264a3de2.js" as="script"><link rel="prefetch" href="/assets/index.html-fb62746d.js" as="script"><link rel="prefetch" href="/assets/index.html-81d28dad.js" as="script"><link rel="prefetch" href="/assets/index.html-56062662.js" as="script"><link rel="prefetch" href="/assets/giscus-0b7adcf8.js" as="script"><link rel="prefetch" href="/assets/photoswipe.esm-1464cdb9.js" as="script"><link rel="prefetch" href="/assets/index-e32a7948.js" as="script">
  </head>
  <body>
    <div id="app"><!--[--><!--[--><!--[--><span tabindex="-1"></span><a href="#main-content" class="vp-skip-link sr-only">跳至主要內容</a><!--]--><!--[--><div class="theme-container has-toc"><!--[--><header id="navbar" class="vp-navbar"><div class="vp-navbar-start"><button type="button" class="vp-toggle-sidebar-button" title="Toggle Sidebar"><span class="icon"></span></button><!--[--><!----><!--]--><!--[--><a class="vp-link vp-brand vp-brand" href="/"><img class="vp-nav-logo" src="https://gitee.com/eddie-lucas/images/raw/master/img/logo.svg" alt="小刘Learning"><!----><span class="vp-site-name hide-in-pad">小刘Learning</span></a><!--]--><!--[--><!----><!--]--></div><div class="vp-navbar-center"><!--[--><!----><!--]--><!--[--><nav class="vp-nav-links"><div class="nav-item hide-in-mobile"><a aria-label="首页" class="vp-link nav-link nav-link" href="/"><span class="font-icon icon iconfont icon-shouye" style=""></span>首页<!----></a></div><div class="nav-item hide-in-mobile"><a aria-label="后端技术" class="vp-link nav-link nav-link" href="/backend/mysql/MySQL%E4%BA%8B%E5%8A%A1%E4%B8%8EMVCC.html"><span class="font-icon icon iconfont icon-xingqiu" style=""></span>后端技术<!----></a></div><div class="nav-item hide-in-mobile"><a aria-label="读书笔记" class="vp-link nav-link nav-link" href="/readNote/redis/Redis%E5%BC%80%E5%8F%91%E4%B8%8E%E8%BF%90%E7%BB%B4.html"><span class="font-icon icon iconfont icon-book" style=""></span>读书笔记<!----></a></div></nav><!--]--><!--[--><!----><!--]--></div><div class="vp-navbar-end"><!--[--><!----><!--]--><!--[--><!----><div class="nav-item vp-repo"><a class="vp-repo-link" href="https://github.com/eddie-lucas" target="_blank" rel="noopener noreferrer" aria-label="GitHub"><svg xmlns="http://www.w3.org/2000/svg" class="icon github-icon" viewBox="0 0 1024 1024" fill="currentColor" aria-label="github icon" style="width:1.25rem;height:1.25rem;vertical-align:middle;"><path d="M511.957 21.333C241.024 21.333 21.333 240.981 21.333 512c0 216.832 140.544 400.725 335.574 465.664 24.49 4.395 32.256-10.07 32.256-23.083 0-11.69.256-44.245 0-85.205-136.448 29.61-164.736-64.64-164.736-64.64-22.315-56.704-54.4-71.765-54.4-71.765-44.587-30.464 3.285-29.824 3.285-29.824 49.195 3.413 75.179 50.517 75.179 50.517 43.776 75.008 114.816 53.333 142.762 40.79 4.523-31.66 17.152-53.377 31.19-65.537-108.971-12.458-223.488-54.485-223.488-242.602 0-53.547 19.114-97.323 50.517-131.67-5.035-12.33-21.93-62.293 4.779-129.834 0 0 41.258-13.184 134.912 50.346a469.803 469.803 0 0 1 122.88-16.554c41.642.213 83.626 5.632 122.88 16.554 93.653-63.488 134.784-50.346 134.784-50.346 26.752 67.541 9.898 117.504 4.864 129.834 31.402 34.347 50.474 78.123 50.474 131.67 0 188.586-114.73 230.016-224.042 242.09 17.578 15.232 33.578 44.672 33.578 90.454v135.85c0 13.142 7.936 27.606 32.854 22.87C862.25 912.597 1002.667 728.747 1002.667 512c0-271.019-219.648-490.667-490.71-490.667z"></path></svg></a></div><div class="nav-item hide-in-mobile"><button type="button" id="appearance-switch"><svg xmlns="http://www.w3.org/2000/svg" class="icon auto-icon" viewBox="0 0 1024 1024" fill="currentColor" aria-label="auto icon" style="display:block;"><path d="M512 992C246.92 992 32 777.08 32 512S246.92 32 512 32s480 214.92 480 480-214.92 480-480 480zm0-840c-198.78 0-360 161.22-360 360 0 198.84 161.22 360 360 360s360-161.16 360-360c0-198.78-161.22-360-360-360zm0 660V212c165.72 0 300 134.34 300 300 0 165.72-134.28 300-300 300z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" class="icon dark-icon" viewBox="0 0 1024 1024" fill="currentColor" aria-label="dark icon" style="display:none;"><path d="M524.8 938.667h-4.267a439.893 439.893 0 0 1-313.173-134.4 446.293 446.293 0 0 1-11.093-597.334A432.213 432.213 0 0 1 366.933 90.027a42.667 42.667 0 0 1 45.227 9.386 42.667 42.667 0 0 1 10.24 42.667 358.4 358.4 0 0 0 82.773 375.893 361.387 361.387 0 0 0 376.747 82.774 42.667 42.667 0 0 1 54.187 55.04 433.493 433.493 0 0 1-99.84 154.88 438.613 438.613 0 0 1-311.467 128z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" class="icon light-icon" viewBox="0 0 1024 1024" fill="currentColor" aria-label="light icon" style="display:none;"><path d="M952 552h-80a40 40 0 0 1 0-80h80a40 40 0 0 1 0 80zM801.88 280.08a41 41 0 0 1-57.96-57.96l57.96-58a41.04 41.04 0 0 1 58 58l-58 57.96zM512 752a240 240 0 1 1 0-480 240 240 0 0 1 0 480zm0-560a40 40 0 0 1-40-40V72a40 40 0 0 1 80 0v80a40 40 0 0 1-40 40zm-289.88 88.08-58-57.96a41.04 41.04 0 0 1 58-58l57.96 58a41 41 0 0 1-57.96 57.96zM192 512a40 40 0 0 1-40 40H72a40 40 0 0 1 0-80h80a40 40 0 0 1 40 40zm30.12 231.92a41 41 0 0 1 57.96 57.96l-57.96 58a41.04 41.04 0 0 1-58-58l58-57.96zM512 832a40 40 0 0 1 40 40v80a40 40 0 0 1-80 0v-80a40 40 0 0 1 40-40zm289.88-88.08 58 57.96a41.04 41.04 0 0 1-58 58l-57.96-58a41 41 0 0 1 57.96-57.96z"></path></svg></button></div><!----><!--]--><!--[--><!----><!--]--><button type="button" class="vp-toggle-navbar-button" aria-label="Toggle Navbar" aria-expanded="false" aria-controls="nav-screen"><span><span class="vp-top"></span><span class="vp-middle"></span><span class="vp-bottom"></span></span></button></div></header><!----><!--]--><!----><div class="toggle-sidebar-wrapper"><span class="arrow start"></span></div><aside id="sidebar" class="vp-sidebar"><!--[--><!----><!--]--><ul class="vp-sidebar-links"><li><section class="vp-sidebar-group"><button class="vp-sidebar-heading clickable" type="button"><span class="font-icon icon iconfont icon-MySQL" style=""></span><span class="vp-sidebar-title">MySQL</span><span class="vp-arrow end"></span></button><!----></section></li><li><section class="vp-sidebar-group"><button class="vp-sidebar-heading clickable" type="button"><span class="font-icon icon iconfont icon-redis" style=""></span><span class="vp-sidebar-title">Redis</span><span class="vp-arrow end"></span></button><!----></section></li><li><section class="vp-sidebar-group"><button class="vp-sidebar-heading clickable active" type="button"><span class="font-icon icon iconfont icon-Spring" style=""></span><span class="vp-sidebar-title">Spring</span><span class="vp-arrow down"></span></button><ul class="vp-sidebar-links"><li><!--[--><a aria-label="Spring4.3.x源码阅读" class="vp-link nav-link active vp-sidebar-link vp-sidebar-page active nav-link active vp-sidebar-link vp-sidebar-page active" href="/backend/spring/Spring4.3.x%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB.html"><!---->Spring4.3.x源码阅读<!----></a><ul class="vp-sidebar-sub-headers"><li class="vp-sidebar-sub-header"><a aria-label="前言" class="vp-link nav-link vp-sidebar-link vp-heading nav-link vp-sidebar-link vp-heading" href="/backend/spring/Spring4.3.x%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB.html#前言"><!---->前言<!----></a><ul class="vp-sidebar-sub-headers"></ul></li><li class="vp-sidebar-sub-header"><a aria-label="如何阅读源码？" class="vp-link nav-link vp-sidebar-link vp-heading nav-link vp-sidebar-link vp-heading" href="/backend/spring/Spring4.3.x%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB.html#如何阅读源码"><!---->如何阅读源码？<!----></a><ul class="vp-sidebar-sub-headers"></ul></li><li class="vp-sidebar-sub-header"><a aria-label="什么是IOC？" class="vp-link nav-link vp-sidebar-link vp-heading nav-link vp-sidebar-link vp-heading" href="/backend/spring/Spring4.3.x%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB.html#什么是ioc"><!---->什么是IOC？<!----></a><ul class="vp-sidebar-sub-headers"></ul></li><li class="vp-sidebar-sub-header"><a aria-label="Spring如何创建对象？" class="vp-link nav-link vp-sidebar-link vp-heading nav-link vp-sidebar-link vp-heading" href="/backend/spring/Spring4.3.x%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB.html#spring如何创建对象"><!---->Spring如何创建对象？<!----></a><ul class="vp-sidebar-sub-headers"><li class="vp-sidebar-sub-header"><a aria-label="refresh()方法及内部重要方法" class="vp-link nav-link vp-sidebar-link vp-heading nav-link vp-sidebar-link vp-heading" href="/backend/spring/Spring4.3.x%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB.html#refresh-方法及内部重要方法"><!---->refresh()方法及内部重要方法<!----></a><ul class="vp-sidebar-sub-headers"></ul></li></ul></li><li class="vp-sidebar-sub-header"><a aria-label="总结" class="vp-link nav-link vp-sidebar-link vp-heading nav-link vp-sidebar-link vp-heading" href="/backend/spring/Spring4.3.x%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB.html#总结"><!---->总结<!----></a><ul class="vp-sidebar-sub-headers"></ul></li></ul><!--]--></li><li><!--[--><a aria-label="过滤器和拦截器的区别" class="vp-link nav-link vp-sidebar-link vp-sidebar-page nav-link vp-sidebar-link vp-sidebar-page" href="/backend/spring/%E8%BF%87%E6%BB%A4%E5%99%A8%E5%92%8C%E6%8B%A6%E6%88%AA%E5%99%A8%E7%9A%84%E5%8C%BA%E5%88%AB.html"><!---->过滤器和拦截器的区别<!----></a><ul class="vp-sidebar-sub-headers"></ul><!--]--></li></ul></section></li><li><section class="vp-sidebar-group"><button class="vp-sidebar-heading clickable" type="button"><span class="font-icon icon iconfont icon-a-icons8-mybatis2" style=""></span><span class="vp-sidebar-title">MyBatis</span><span class="vp-arrow end"></span></button><!----></section></li><li><section class="vp-sidebar-group"><button class="vp-sidebar-heading clickable" type="button"><span class="font-icon icon iconfont icon-xxl-job" style=""></span><span class="vp-sidebar-title">XXL-JOB</span><span class="vp-arrow end"></span></button><!----></section></li><li><section class="vp-sidebar-group"><button class="vp-sidebar-heading clickable" type="button"><span class="font-icon icon iconfont icon-RocketMQ" style=""></span><span class="vp-sidebar-title">RocketMQ 4.6.0</span><span class="vp-arrow end"></span></button><!----></section></li><li><section class="vp-sidebar-group"><button class="vp-sidebar-heading clickable" type="button"><span class="font-icon icon iconfont icon-Netty" style=""></span><span class="vp-sidebar-title">Netty</span><span class="vp-arrow end"></span></button><!----></section></li><li><section class="vp-sidebar-group"><button class="vp-sidebar-heading clickable" type="button"><span class="font-icon icon iconfont icon-tools" style=""></span><span class="vp-sidebar-title">工具安装教程</span><span class="vp-arrow end"></span></button><!----></section></li></ul><!--[--><!----><!--]--></aside><!--[--><main id="main-content" class="vp-page"><!--[--><!--[--><!----><!--]--><!----><nav class="vp-breadcrumb disable"></nav><div class="vp-page-title"><h1><!---->Spring4.3.x源码阅读</h1><div class="page-info"><span class="page-author-info" aria-label="作者🖊" data-balloon-pos="down"><svg xmlns="http://www.w3.org/2000/svg" class="icon author-icon" viewBox="0 0 1024 1024" fill="currentColor" aria-label="author icon"><path d="M649.6 633.6c86.4-48 147.2-144 147.2-249.6 0-160-128-288-288-288s-288 128-288 288c0 108.8 57.6 201.6 147.2 249.6-121.6 48-214.4 153.6-240 288-3.2 9.6 0 19.2 6.4 25.6 3.2 9.6 12.8 12.8 22.4 12.8h704c9.6 0 19.2-3.2 25.6-12.8 6.4-6.4 9.6-16 6.4-25.6-25.6-134.4-121.6-240-243.2-288z"></path></svg><span><span class="page-author-item">小刘Learning</span></span><span property="author" content="小刘Learning"></span></span><!----><span class="page-date-info" aria-label="写作日期📅" data-balloon-pos="down"><svg xmlns="http://www.w3.org/2000/svg" class="icon calendar-icon" viewBox="0 0 1024 1024" fill="currentColor" aria-label="calendar icon"><path d="M716.4 110.137c0-18.753-14.72-33.473-33.472-33.473-18.753 0-33.473 14.72-33.473 33.473v33.473h66.993v-33.473zm-334.87 0c0-18.753-14.72-33.473-33.473-33.473s-33.52 14.72-33.52 33.473v33.473h66.993v-33.473zm468.81 33.52H716.4v100.465c0 18.753-14.72 33.473-33.472 33.473a33.145 33.145 0 01-33.473-33.473V143.657H381.53v100.465c0 18.753-14.72 33.473-33.473 33.473a33.145 33.145 0 01-33.473-33.473V143.657H180.6A134.314 134.314 0 0046.66 277.595v535.756A134.314 134.314 0 00180.6 947.289h669.74a134.36 134.36 0 00133.94-133.938V277.595a134.314 134.314 0 00-133.94-133.938zm33.473 267.877H147.126a33.145 33.145 0 01-33.473-33.473c0-18.752 14.72-33.473 33.473-33.473h736.687c18.752 0 33.472 14.72 33.472 33.473a33.145 33.145 0 01-33.472 33.473z"></path></svg><span><!----></span><meta property="datePublished" content="2024-08-16T09:13:59.000Z"></span><!----><span class="page-reading-time-info" aria-label="阅读时间⌛" data-balloon-pos="down"><svg xmlns="http://www.w3.org/2000/svg" class="icon timer-icon" viewBox="0 0 1024 1024" fill="currentColor" aria-label="timer icon"><path d="M799.387 122.15c4.402-2.978 7.38-7.897 7.38-13.463v-1.165c0-8.933-7.38-16.312-16.312-16.312H256.33c-8.933 0-16.311 7.38-16.311 16.312v1.165c0 5.825 2.977 10.874 7.637 13.592 4.143 194.44 97.22 354.963 220.201 392.763-122.204 37.542-214.893 196.511-220.2 389.397-4.661 5.049-7.638 11.651-7.638 19.03v5.825h566.49v-5.825c0-7.379-2.849-13.981-7.509-18.9-5.049-193.016-97.867-351.985-220.2-389.527 123.24-37.67 216.446-198.453 220.588-392.892zM531.16 450.445v352.632c117.674 1.553 211.787 40.778 211.787 88.676H304.097c0-48.286 95.149-87.382 213.728-88.676V450.445c-93.077-3.107-167.901-81.297-167.901-177.093 0-8.803 6.99-15.793 15.793-15.793 8.803 0 15.794 6.99 15.794 15.793 0 80.261 63.69 145.635 142.01 145.635s142.011-65.374 142.011-145.635c0-8.803 6.99-15.793 15.794-15.793s15.793 6.99 15.793 15.793c0 95.019-73.789 172.82-165.96 177.093z"></path></svg><span>大约 14 分钟</span><meta property="timeRequired" content="PT14M"></span><!----><!----></div><hr></div><div class="toc-place-holder"><aside id="toc"><!--[--><!----><!--]--><div class="toc-header">此页内容<button type="button" class="print-button" title="打印"><svg xmlns="http://www.w3.org/2000/svg" class="icon print-icon" viewBox="0 0 1024 1024" fill="currentColor" aria-label="print icon"><path d="M819.2 364.8h-44.8V128c0-17.067-14.933-32-32-32H281.6c-17.067 0-32 14.933-32 32v236.8h-44.8C145.067 364.8 96 413.867 96 473.6v192c0 59.733 49.067 108.8 108.8 108.8h44.8V896c0 17.067 14.933 32 32 32h460.8c17.067 0 32-14.933 32-32V774.4h44.8c59.733 0 108.8-49.067 108.8-108.8v-192c0-59.733-49.067-108.8-108.8-108.8zM313.6 160h396.8v204.8H313.6V160zm396.8 704H313.6V620.8h396.8V864zM864 665.6c0 25.6-19.2 44.8-44.8 44.8h-44.8V588.8c0-17.067-14.933-32-32-32H281.6c-17.067 0-32 14.933-32 32v121.6h-44.8c-25.6 0-44.8-19.2-44.8-44.8v-192c0-25.6 19.2-44.8 44.8-44.8h614.4c25.6 0 44.8 19.2 44.8 44.8v192z"></path></svg></button></div><div class="toc-wrapper"><ul class="toc-list"><!--[--><li class="toc-item"><a class="vp-link toc-link level2 toc-link level2" href="#前言">前言</a></li><!----><!--]--><!--[--><li class="toc-item"><a class="vp-link toc-link level2 toc-link level2" href="#如何阅读源码">如何阅读源码？</a></li><!----><!--]--><!--[--><li class="toc-item"><a class="vp-link toc-link level2 toc-link level2" href="#什么是ioc">什么是IOC？</a></li><!----><!--]--><!--[--><li class="toc-item"><a class="vp-link toc-link level2 toc-link level2" href="#spring如何创建对象">Spring如何创建对象？</a></li><li><ul class="toc-list"><!--[--><li class="toc-item"><a class="vp-link toc-link level3 toc-link level3" href="#refresh-方法及内部重要方法">refresh()方法及内部重要方法</a></li><!----><!--]--></ul></li><!--]--><!--[--><li class="toc-item"><a class="vp-link toc-link level2 toc-link level2" href="#总结">总结</a></li><!----><!--]--></ul><div class="toc-marker" style="top:-1.7rem;"></div></div><!--[--><!----><!--]--></aside></div><!--[--><!----><!--]--><div class="theme-hope-content"><h2 id="前言" tabindex="-1"><a class="header-anchor" href="#前言" aria-hidden="true">#</a> 前言</h2><p>作为Java程序员，一定会和Spring打交道，最初学习Spring的时候，也是跟着视频，按照老师的操作，一步步学着如何使用Spring，慢慢的，了解到一些重点概念，比如IOC，AOP等，当初学习的时候就觉得Spring好神奇，好厉害，就越发的想要了解其背后的原理，下文会围绕Spring的核心概念以及工作中会接触到的知识点，来阅读Spring的源码，揭开Spring的神秘面纱。</p><h2 id="如何阅读源码" tabindex="-1"><a class="header-anchor" href="#如何阅读源码" aria-hidden="true">#</a> 如何阅读源码？</h2><p>作为一个程序员，不仅需要能够使用各种不同的技术，并且需要了解这些技术底层的原理，阅读源码是程序员的必备技能之一，那么对新技术，新框架，应该要如何正确的去阅读源码呢？下面是我个人的一些观点，如果你有更好的方法，也可以分享给大家，让大家也能学习优秀程序员的学习习惯。</p><ol><li>首先要会使用这项技术，只有能够熟练的使用了，再去了解底层的源码才能够得心应手</li><li>了解该技术的重点概念及知识，这一点，其实在学习使用技术的时候，也会慢慢接触，会有一个基本印象</li><li>阅读源码不像读书，从头看到尾，而是有重点的去看，并不需要了解这项技术的所有细节，看不完的</li><li>阅读源码的时候应该由契合重点概念及核心知识的小demo入手，由浅入深，了解简单demo背后的原理</li><li>阅读源码不需要一次性看完所有重点，当在工作中碰到某个知识点的使用的时候，想要了解背后的原理，可以针对这个点来看相关的源码</li></ol><h2 id="什么是ioc" tabindex="-1"><a class="header-anchor" href="#什么是ioc" aria-hidden="true">#</a> 什么是IOC？</h2><p>所谓<code>IOC就是控制反转</code>，之前，对象都由我们去创建，现在将创建对象的工作交给Spring，并且让Spring去控制管理这些对象，在Spring中将对象称为bean，bean翻译为豆子，豆形种子，豆科植物，Spring翻译为春天，Spring是一个容器，用来容纳这些bean，在春天里，这些bean在Spring容器的土壤中生根发芽，历经枯荣（bean的生命周期），有了Spring，程序员也更加轻松，因此Spring是程序员的春天。</p><h2 id="spring如何创建对象" tabindex="-1"><a class="header-anchor" href="#spring如何创建对象" aria-hidden="true">#</a> Spring如何创建对象？</h2><p>了解了什么是IOC，那么Spring是如何去帮助我们创建对象的呢？不妨回忆一下最开始学习的时候，是如何使用Spirng的，相信大家对这个demo一定不陌生：</p><ol><li>在xml文件中配置bean的信息</li></ol><div class="language-xml line-numbers-mode" data-ext="xml"><pre class="language-xml"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>bean</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>user<span class="token punctuation">&quot;</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>org.example.entity.User<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>property</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>username<span class="token punctuation">&quot;</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>lisi<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>property</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>property</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>password<span class="token punctuation">&quot;</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>123456<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>property</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>bean</span><span class="token punctuation">&gt;</span></span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><ol start="2"><li>通过<code>ClassPathXmlApplicationContext</code>类读取该xml文件，然后通过<code>getBean()</code>去获取需要的bean对象</li></ol><div class="language-java line-numbers-mode" data-ext="java"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">IOCTest</span> <span class="token punctuation">{</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">//读取xml文件</span>
        <span class="token class-name">ApplicationContext</span> context <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ClassPathXmlApplicationContext</span><span class="token punctuation">(</span><span class="token string">&quot;beans.xml&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>context<span class="token punctuation">.</span><span class="token function">getBean</span><span class="token punctuation">(</span><span class="token string">&quot;user&quot;</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>现在，就从这个demo入手，去深入了解Spring是如何创建一个对象的。首先，需要介绍一下<code>ClassPathXmlApplicationContext</code>，见名知意，这个类是针对classpath，即类路径下的xml文件的，它属于<code>ApplicationContext</code>，即应用上下文。</p><blockquote><p><strong>上下文的含义</strong>就像一篇文章的上文和下文一样，这个概念我也是接触多了，然后自己认为这样比较好理解，你在文章的当前段落，可以看到该文章上面的段落和下面的段落，这里的文章就是应用，通过ApplicationContext，可以在应用中任何地方获取到放在ApplicationContext中的东西，也就是说ApplicationContext就是应用的容器，用来装应用中的对象</p></blockquote><figure><img src="https://gitee.com/eddie-lucas/images/raw/master/img/image-20240308205350613.png" alt="简化关系图" tabindex="0" loading="lazy"><figcaption>简化关系图</figcaption></figure><blockquote><p>这里再补充一下，接口是代表行为的，类是代表从属关系的，即<strong>接口代表能不能，类代表是不是</strong>，例如飞机是交通工具类，老鹰是鸟类，它们都能飞（行为）</p></blockquote><p>由上面的简化关系图可知，<code>ClassPathXmlApplicationContext</code>能够加载资源（ResourceLoader），能够创建，获取bean（BeanFactory），通过它可以操作Spring这个容器，或者也可以理解为，它就是容器。</p><p>要想了解Spring是如何创建对象的，首先需要知道，在创建<code>ClassPathXmlApplicationContext</code>的过程中，到底做了什么，下面就开始逐步深入。</p><figure><img src="https://gitee.com/eddie-lucas/images/raw/master/img/image-20240308211320824.png" alt="构造方法注释" tabindex="0" loading="lazy"><figcaption>构造方法注释</figcaption></figure><div class="language-java line-numbers-mode" data-ext="java"><pre class="language-java"><code>
<span class="token keyword">public</span> <span class="token class-name">ClassPathXmlApplicationContext</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> configLocations<span class="token punctuation">,</span> <span class="token keyword">boolean</span> refresh<span class="token punctuation">,</span> <span class="token class-name">ApplicationContext</span> parent<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">BeansException</span> <span class="token punctuation">{</span>
    <span class="token comment">//本质上就是创建了一个AbstractApplicationContext对象，同时指定了资源解析器</span>
    <span class="token keyword">super</span><span class="token punctuation">(</span>parent<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//parent：null</span>
    <span class="token comment">//设置context的configLocations属性，本类中没有这个属性，继承而来</span>
    <span class="token function">setConfigLocations</span><span class="token punctuation">(</span>configLocations<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>refresh<span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token comment">//true，自动刷新上下文，加载所有的beanDefiniton，创建所有的单例，false则需要手动调用</span>
        <span class="token function">refresh</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>在这个构造方法中，前两行代码并不是很重要，就是创建了context对象，并且设置了configLocations属性，即告诉context去哪里找xml配置文件。</p><p>重要的是<code>refresh()</code>方法，通过注释可以看到，这个方法会自动刷新context，加载所有的beanDefiniton，创建所有的单例对象，也就是说，我们需要的对象是在这个方法中创建出来的，这个方法到底做了什么，继续往下看。</p><p>上面这段话中有一些陌生的概念：</p><ul><li><p>beanDefiniton（bean的定义信息）</p><p>也就是我们自己定义的bean的信息，它是哪个类，有哪些属性，这些属性的值是什么</p></li><li><p>单例对象</p><p>这个就涉及到了单例模式，Spring是采用单例模式的，即一个类只有一个对象</p></li></ul><h3 id="refresh-方法及内部重要方法" tabindex="-1"><a class="header-anchor" href="#refresh-方法及内部重要方法" aria-hidden="true">#</a> refresh()方法及内部重要方法</h3><p>先来看一下<code>refresh()</code>方法的源码：</p><div class="language-java line-numbers-mode" data-ext="java"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">refresh</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">BeansException</span><span class="token punctuation">,</span> <span class="token class-name">IllegalStateException</span> <span class="token punctuation">{</span>
    <span class="token keyword">synchronized</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>startupShutdownMonitor<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token doc-comment comment">/**
			 * 为context刷新做一些准备工作
			 * 设置容器启动时间
			 * 设置活跃状态为true
			 * 设置关闭状态为false
			 * 获取Environment对象，并加载当前系统的属性值到该对象中
			 * 准备监听器和事件的集合对象，默认为空集合
			 */</span>
        <span class="token function">prepareRefresh</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token comment">// Tell the subclass to refresh the internal bean factory.</span>
        <span class="token comment">//创建了DefaultListableBeanFactory，同时将beanDefinition放进了map（debug打点）</span>
        <span class="token class-name">ConfigurableListableBeanFactory</span> beanFactory <span class="token operator">=</span> <span class="token function">obtainFreshBeanFactory</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token comment">// Prepare the bean factory for use in this context.</span>
        <span class="token comment">//beanFactory准备工作，对beanFactory各种属性进行填充</span>
        <span class="token function">prepareBeanFactory</span><span class="token punctuation">(</span>beanFactory<span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">try</span> <span class="token punctuation">{</span>
            <span class="token comment">// Allows post-processing of the bean factory in context subclasses.</span>
            <span class="token comment">//由子类覆盖方法做额外处理，此处我们一般不做任何扩展</span>
            <span class="token function">postProcessBeanFactory</span><span class="token punctuation">(</span>beanFactory<span class="token punctuation">)</span><span class="token punctuation">;</span>

            <span class="token comment">// Invoke factory processors registered as beans in the context.</span>
            <span class="token comment">//调用各种BeanFactoryPostProcessor</span>
            <span class="token function">invokeBeanFactoryPostProcessors</span><span class="token punctuation">(</span>beanFactory<span class="token punctuation">)</span><span class="token punctuation">;</span>

            <span class="token comment">// Register bean processors that intercept bean creation.</span>
            <span class="token comment">//注册BeanPostProcessor，并没有调用</span>
            <span class="token function">registerBeanPostProcessors</span><span class="token punctuation">(</span>beanFactory<span class="token punctuation">)</span><span class="token punctuation">;</span>

            <span class="token comment">// Initialize message source for this context.</span>
            <span class="token comment">//用于国际化处理</span>
            <span class="token function">initMessageSource</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

            <span class="token comment">// Initialize event multicaster for this context.</span>
            <span class="token comment">//初始化事件事件广播器</span>
            <span class="token function">initApplicationEventMulticaster</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

            <span class="token comment">// Initialize other special beans in specific context subclasses.</span>
            <span class="token comment">//留给子类扩展，初始化子类的bean</span>
            <span class="token function">onRefresh</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

            <span class="token comment">// Check for listener beans and register them.</span>
            <span class="token comment">//注册监听器</span>
            <span class="token function">registerListeners</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

            <span class="token comment">// Instantiate all remaining (non-lazy-init) singletons.</span>
            <span class="token comment">//实例化非懒加载的单例对象</span>
            <span class="token function">finishBeanFactoryInitialization</span><span class="token punctuation">(</span>beanFactory<span class="token punctuation">)</span><span class="token punctuation">;</span>

            <span class="token comment">// Last step: publish corresponding event.</span>
            <span class="token function">finishRefresh</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">BeansException</span> ex<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span>logger<span class="token punctuation">.</span><span class="token function">isWarnEnabled</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                logger<span class="token punctuation">.</span><span class="token function">warn</span><span class="token punctuation">(</span><span class="token string">&quot;Exception encountered during context initialization - &quot;</span> <span class="token operator">+</span>
                            <span class="token string">&quot;cancelling refresh attempt: &quot;</span> <span class="token operator">+</span> ex<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>

            <span class="token comment">// Destroy already created singletons to avoid dangling resources.</span>
            <span class="token function">destroyBeans</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

            <span class="token comment">// Reset &#39;active&#39; flag.</span>
            <span class="token function">cancelRefresh</span><span class="token punctuation">(</span>ex<span class="token punctuation">)</span><span class="token punctuation">;</span>

            <span class="token comment">// Propagate exception to caller.</span>
            <span class="token keyword">throw</span> ex<span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        <span class="token keyword">finally</span> <span class="token punctuation">{</span>
            <span class="token comment">// Reset common introspection caches in Spring&#39;s core, since we</span>
            <span class="token comment">// might not ever need metadata for singleton beans anymore...</span>
            <span class="token function">resetCommonCaches</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="preparerefresh-方法" tabindex="-1"><a class="header-anchor" href="#preparerefresh-方法" aria-hidden="true">#</a> prepareRefresh()方法</h4><blockquote><p>现在先来了解一下<code>prepareRefresh()</code>到底做了什么</p></blockquote><div class="language-java line-numbers-mode" data-ext="java"><pre class="language-java"><code><span class="token keyword">protected</span> <span class="token keyword">void</span> <span class="token function">prepareRefresh</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">//设置一些初始值，比如启动时间，一些标志位</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>startupDate <span class="token operator">=</span> <span class="token class-name">System</span><span class="token punctuation">.</span><span class="token function">currentTimeMillis</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>closed<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>active<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">if</span> <span class="token punctuation">(</span>logger<span class="token punctuation">.</span><span class="token function">isInfoEnabled</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        logger<span class="token punctuation">.</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string">&quot;Refreshing &quot;</span> <span class="token operator">+</span> <span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">// Initialize any placeholder property sources in the context environment</span>
    <span class="token comment">//这是一个空方法，留给子类扩展</span>
    <span class="token function">initPropertySources</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token comment">// Validate that all properties marked as required are resolvable</span>
    <span class="token comment">// see ConfigurablePropertyResolver#setRequiredProperties</span>
    <span class="token comment">//验证required的属性不能为null（vm options）</span>
    <span class="token function">getEnvironment</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">validateRequiredProperties</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token comment">// Allow for the collection of early ApplicationEvents,</span>
    <span class="token comment">// to be published once the multicaster is available...</span>
    <span class="token comment">//创建一个空的Set</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>earlyApplicationEvents <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">LinkedHashSet</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">ApplicationEvent</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>在这个方法中，<code>initPropertySources()</code>是抽象类<code>AbstractApplicationContext</code>中的空方法，可以通过子类继承，然后重写的方式，由我们自己去扩展。</p><p><code>getEnvironment().validateRequiredProperties()</code>是去验证一些required的<code>vm options</code>不能为null</p><figure><img src="https://gitee.com/eddie-lucas/images/raw/master/img/image-20240309092506289.png" alt="设置属性和验证属性" tabindex="0" loading="lazy"><figcaption>设置属性和验证属性</figcaption></figure><p>默认情况下，这个<code>requiredProperties</code>的size为0，因为required的属性需要由我们自己去指定，也就是需要由我们去告诉Spring，启动的时候需要哪些属性，否则就不能启动。</p><p>那又该在哪里去指定这些属性呢？当然是在验证属性是否为null的前一步，即<code>initPropertySources()</code>中指定必需属性，现在，来写一个自己的类，继承<code>ClassPathXmlApplicationContext</code>（它间接的继承了AbstractApplicationContext）</p><div class="language-java line-numbers-mode" data-ext="java"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">MyXMLContext</span> <span class="token keyword">extends</span> <span class="token class-name">ClassPathXmlApplicationContext</span> <span class="token punctuation">{</span>
    <span class="token comment">//构造方法，直接调用ClassPathXmlApplicationContext的构造方法，即跟上面流程一样</span>
    <span class="token keyword">public</span> <span class="token class-name">MyXMLContext</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span> configLocations<span class="token punctuation">)</span><span class="token punctuation">{</span>
        <span class="token keyword">super</span><span class="token punctuation">(</span>configLocations<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token comment">//抽象类是不能被实例化的，当调用抽象类的该方法时，会调用其子类的该方法</span>
    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">protected</span> <span class="token keyword">void</span> <span class="token function">initPropertySources</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;扩展initPropertySources....&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">//要求必须提供MYSQL_HOST参数（vm options），否则不能正常启动</span>
        <span class="token function">getEnvironment</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">setRequiredProperties</span><span class="token punctuation">(</span><span class="token string">&quot;MYSQL_HOST&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">MyXMLContext</span> context <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">MyXMLContext</span><span class="token punctuation">(</span><span class="token string">&quot;beans.xml&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>context<span class="token punctuation">.</span><span class="token function">getBean</span><span class="token punctuation">(</span><span class="token string">&quot;user&quot;</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>首先，不指定MYSQL_HOST属性启动，则会报错</p><figure><img src="https://gitee.com/eddie-lucas/images/raw/master/img/image-20240309094339762.png" alt="不指定异常图" tabindex="0" loading="lazy"><figcaption>不指定异常图</figcaption></figure><p>接着，在idea中通过-D指定该vm属性，在VM options中填入<code>-DMYSQL_HOST=127.0.0.1</code>，然后发现能够正常启动，不报错</p><figure><img src="https://gitee.com/eddie-lucas/images/raw/master/img/image-20240309094614224.png" alt="idea配置面板" tabindex="0" loading="lazy"><figcaption>idea配置面板</figcaption></figure><blockquote><p>这里说一下，<code>VM Options</code>，<code>Program Arguments</code>，<code>Environment Variables</code>的区别，VM Options是JVM参数，Program Arguments是交给main方法的args的参数，Environment Variables是环境变量，安装JDK，配置操作系统的环境变量就是这个东西</p></blockquote><table><thead><tr><th>参数</th><th>使用方法</th><th>实例</th><th>代码获取方式</th></tr></thead><tbody><tr><td>VM Options</td><td>必须以-D 、 -X 、 -XX 开头，每个参数用空格隔开</td><td>-Dvm.key=VmKey -Xms2048m</td><td>String key = System.getProperty(“vm.key”);</td></tr><tr><td>Program Arguments</td><td>每个参数用空格隔开</td><td>p.key=Program_Key p.name=ProgramName p.age=18</td><td>main(String[] args)</td></tr><tr><td>Environment Variables</td><td><strong>其优先级低于 VM options</strong> ，即如果VM options 有一个变量和 Environment variable中的变量的key相同，则以VM options 中为准， 以分号分割多个</td><td>env.key=env_james;server.servlet.context-path=/test;server.port=8080</td><td>String envKey = System.getenv(“env.key”);</td></tr></tbody></table><h4 id="obtainfreshbeanfactory-方法" tabindex="-1"><a class="header-anchor" href="#obtainfreshbeanfactory-方法" aria-hidden="true">#</a> obtainFreshBeanFactory()方法</h4><p>见名知意，通过这个方法，可以获得一个BeanFactory</p><div class="language-java line-numbers-mode" data-ext="java"><pre class="language-java"><code><span class="token keyword">protected</span> <span class="token class-name">ConfigurableListableBeanFactory</span> <span class="token function">obtainFreshBeanFactory</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">//创建了beanFactory</span>
    <span class="token function">refreshBeanFactory</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">//将上面创建的beanFactory进一步包装为ConfigurableListableBeanFactory</span>
    <span class="token class-name">ConfigurableListableBeanFactory</span> beanFactory <span class="token operator">=</span> <span class="token function">getBeanFactory</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>logger<span class="token punctuation">.</span><span class="token function">isDebugEnabled</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        logger<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">&quot;Bean factory for &quot;</span> <span class="token operator">+</span> <span class="token function">getDisplayName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">&quot;: &quot;</span> <span class="token operator">+</span> beanFactory<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">return</span> beanFactory<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>这个方法中重要的是<code>refreshBeanFactory()</code></p><div class="language-java line-numbers-mode" data-ext="java"><pre class="language-java"><code><span class="token keyword">protected</span> <span class="token keyword">final</span> <span class="token keyword">void</span> <span class="token function">refreshBeanFactory</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">BeansException</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">hasBeanFactory</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token comment">//false</span>
        <span class="token function">destroyBeans</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token function">closeBeanFactory</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">try</span> <span class="token punctuation">{</span>
        <span class="token comment">//创建一个DefaultListableBeanFactory</span>
        <span class="token class-name">DefaultListableBeanFactory</span> beanFactory <span class="token operator">=</span> <span class="token function">createBeanFactory</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">//设置序列化id</span>
        beanFactory<span class="token punctuation">.</span><span class="token function">setSerializationId</span><span class="token punctuation">(</span><span class="token function">getId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">//可以自定义beanFactory</span>
        <span class="token function">customizeBeanFactory</span><span class="token punctuation">(</span>beanFactory<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">//在这个方法中将beanDefinition放到了beanFactory的beanDefinitionMap中</span>
        <span class="token function">loadBeanDefinitions</span><span class="token punctuation">(</span>beanFactory<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">synchronized</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>beanFactoryMonitor<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">this</span><span class="token punctuation">.</span>beanFactory <span class="token operator">=</span> beanFactory<span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">IOException</span> ex<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">ApplicationContextException</span><span class="token punctuation">(</span><span class="token string">&quot;I/O error parsing bean definition source for &quot;</span> <span class="token operator">+</span> <span class="token function">getDisplayName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> ex<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>上面的代码中有一个可以自定义的地方，通过继承并重写<code>AbstractRefreshableApplicationContext</code>中的<code>customizeBeanFactory()</code>方法，可以自定义DefaultListableBeanFactory的任何设置，在默认情况下，customizeBeanFactory()方法什么也没做，这两个标志位，默认都为true，即<strong>默认允许重写BeanDefinition，允许循环引用</strong></p><div class="language-java line-numbers-mode" data-ext="java"><pre class="language-java"><code><span class="token keyword">protected</span> <span class="token keyword">void</span> <span class="token function">customizeBeanFactory</span><span class="token punctuation">(</span><span class="token class-name">DefaultListableBeanFactory</span> beanFactory<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>allowBeanDefinitionOverriding <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token comment">//null</span>
        beanFactory<span class="token punctuation">.</span><span class="token function">setAllowBeanDefinitionOverriding</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>allowBeanDefinitionOverriding<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>allowCircularReferences <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token comment">//null</span>
        beanFactory<span class="token punctuation">.</span><span class="token function">setAllowCircularReferences</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>allowCircularReferences<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote><p>什么是循环引用？这个将在其他文章中进行讲解</p></blockquote><p>在上面的代码中，已经将beanFactory创建出来了，beanFactory是用来创建Bean的，要创建bean，首先需要将我们自己定义的bean的信息告诉它，即beanDefinition，它才能根据里面的信息来创建，所以<code>loadBeanDefinitions()</code>是非常重要的方法</p><div class="language-java line-numbers-mode" data-ext="java"><pre class="language-java"><code><span class="token keyword">protected</span> <span class="token keyword">void</span> <span class="token function">loadBeanDefinitions</span><span class="token punctuation">(</span><span class="token class-name">DefaultListableBeanFactory</span> beanFactory<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">BeansException</span><span class="token punctuation">,</span> <span class="token class-name">IOException</span> <span class="token punctuation">{</span>
    <span class="token comment">// Create a new XmlBeanDefinitionReader for the given BeanFactory.</span>
    <span class="token comment">//给BeanFactory创建一个XmlBeanDefinitionReader，它是一个读取器，读取xml文件中的beanDefinition</span>
    <span class="token class-name">XmlBeanDefinitionReader</span> beanDefinitionReader <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">XmlBeanDefinitionReader</span><span class="token punctuation">(</span>beanFactory<span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token comment">// Configure the bean definition reader with this context&#39;s</span>
    <span class="token comment">// resource loading environment.</span>
    <span class="token comment">//开始给beanDefinitionReader填充一些属性</span>
    beanDefinitionReader<span class="token punctuation">.</span><span class="token function">setEnvironment</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getEnvironment</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">//this是ClassPathXmlApplicationContext，它继承了一个configLocations的属性</span>
    <span class="token comment">//相当于告诉beanDefinitionReader xml文件的位置</span>
    beanDefinitionReader<span class="token punctuation">.</span><span class="token function">setResourceLoader</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">//设置解析器</span>
    beanDefinitionReader<span class="token punctuation">.</span><span class="token function">setEntityResolver</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">ResourceEntityResolver</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token comment">// Allow a subclass to provide custom initialization of the reader,</span>
    <span class="token comment">// then proceed with actually loading the bean definitions.</span>
    <span class="token comment">//允许自定义beanDefinitionReader的初始化方法，通常不需要自定义</span>
    <span class="token function">initBeanDefinitionReader</span><span class="token punctuation">(</span>beanDefinitionReader<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">//开始loadBeanDefinitions</span>
    <span class="token function">loadBeanDefinitions</span><span class="token punctuation">(</span>beanDefinitionReader<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><figure><img src="https://gitee.com/eddie-lucas/images/raw/master/img/image-20240309125343073.png" alt="beanDefinitionReader属性图" tabindex="0" loading="lazy"><figcaption>beanDefinitionReader属性图</figcaption></figure><p>跳过一些不重要的代码，来看核心代码，其位于<code>XmlBeanDefinitionReader</code>类和<code>DefaultBeanDefinitionDocumentReader</code>类中，核心方法调用流程图如下：</p><figure><img src="https://gitee.com/eddie-lucas/images/raw/master/img/加载注册beanDefinition核心方法流程图.png" alt="核心方法调用流程图" tabindex="0" loading="lazy"><figcaption>核心方法调用流程图</figcaption></figure><p>整个过程可以概括为，Spring通过XmlBeanDefinitionReader和DefaultBeanDefinitionDocumentReader去读取xml文件，将其中的标签进行解析，对于bean标签，会解析出beanName和beanDefinition</p><ul><li>beanName：和bean标签中的id的值相同</li><li>beanDefinition：bean的定义信息，记录了bean的类，属性值等信息</li></ul><p>然后会将二者以键值对的形式放入到<code>beanDefinitionMap</code>中，它是一个初始大小为256的ConcurrentHashMap，另外，<strong>还将beanName放入到一个大小为256的ArrayList中</strong></p><p>上面提到的只是针对于xml文件来创建对象的过程，如果是以注解的形式，就会有所不同，比如使用的是<code>AnnotatedBeanDefinitionReader</code>，但是大致的过程还是差不多的。</p><h4 id="invokebeanfactorypostprocessors-方法" tabindex="-1"><a class="header-anchor" href="#invokebeanfactorypostprocessors-方法" aria-hidden="true">#</a> invokeBeanFactoryPostProcessors()方法</h4><p>这个方法是调用BeanFactoryPostProcessor，PostProcessor翻译过来是<code>后置处理器</code>，即<strong>创建BeanFactory之后，实例化bean之前，可以进行一些处理操作。</strong></p><p>BeanFactoryPostProcessor到底有什么作用呢？主要是在bean实例化之前，对bean的定义进行修改，例如，可以修改bean的scope，是否懒加载，是否抽象，以及bean的属性值。</p><blockquote><p>如何使用BeanFactoryPostProcessor？</p></blockquote><p>要使用BeanFactoryPostProcessor，需要创建一个实现了BeanFactoryPostProcessor接口的类，并且重写<code>postProcessBeanFactory()</code>，在这个方法中，能够获取到ConfigurableListableBeanFactory，通过它，可以对bean的定义进行修改。</p><div class="language-java line-numbers-mode" data-ext="java"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">CustomBeanFactoryPostProcessor</span> <span class="token keyword">implements</span> <span class="token class-name">BeanFactoryPostProcessor</span> <span class="token punctuation">{</span>

    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">postProcessBeanFactory</span><span class="token punctuation">(</span><span class="token class-name">ConfigurableListableBeanFactory</span> beanFactory<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">BeansException</span> <span class="token punctuation">{</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;user-----执行了BeanFactoryPostProcessor方法.......&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 获取bean定义</span>
        <span class="token class-name">BeanDefinition</span> beanDefinition <span class="token operator">=</span> beanFactory<span class="token punctuation">.</span><span class="token function">getBeanDefinition</span><span class="token punctuation">(</span><span class="token string">&quot;user&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 修改bean定义</span>
        beanDefinition<span class="token punctuation">.</span><span class="token function">setScope</span><span class="token punctuation">(</span><span class="token class-name">BeanDefinition</span><span class="token punctuation">.</span><span class="token constant">SCOPE_PROTOTYPE</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote><p>Spring是如何知道要调用哪些BeanFactoryPostProcessor，调用的顺序又是怎样的？</p></blockquote><p>核心代码：</p><div class="language-java line-numbers-mode" data-ext="java"><pre class="language-java"><code><span class="token comment">//BeanDefinitionRegistryPostProcessor继承了BeanFactoryPostProcessor接口</span>
<span class="token comment">//就理解为BeanFactoryPostProcessor就行了</span>
<span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> postProcessorNames <span class="token operator">=</span>
    beanFactory<span class="token punctuation">.</span><span class="token function">getBeanNamesForType</span><span class="token punctuation">(</span><span class="token class-name">BeanDefinitionRegistryPostProcessor</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>简单来说，就是判断我们注册的bean是不是BeanFactoryPostProcessor类型的，如果是就收集起来，然后开始执行这些BeanFactoryPostProcessor</p><p><strong>BeanFactoryPostProcessor的执行顺序</strong>如下：</p><ol><li>实现了PriorityOrdered接口的，需要重写<code>getOrder()</code>其返回一个整数，<strong>整数越小，优先级越高</strong></li><li>实现了Ordered接口的，需要重写<code>getOrder()</code>其返回一个整数，<strong>整数越小，优先级越高</strong></li><li>调用其他的BeanFactoryPostProcessor</li></ol><h4 id="finishbeanfactoryinitialization-方法" tabindex="-1"><a class="header-anchor" href="#finishbeanfactoryinitialization-方法" aria-hidden="true">#</a> finishBeanFactoryInitialization()方法</h4><p>根据注释，可以知道，在这个方法中创建（实例化+初始化）了所有的非懒加载的单例对象，方法内部比较复杂，其<strong>核心代码是通过反射来创建bean</strong></p><div class="language-java line-numbers-mode" data-ext="java"><pre class="language-java"><code><span class="token class-name">Constructor</span> ctor <span class="token operator">=</span> clazz<span class="token punctuation">.</span><span class="token function">getDeclaredConstructor</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//无参构造器</span>
<span class="token class-name">Object</span> object <span class="token operator">=</span> ctor<span class="token punctuation">.</span><span class="token function">newInstance</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//创建对象</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div></div></div><p>上面的核心代码仅仅是完成了实例化的过程，没有完成初始化过程，即还未对对象的属性进行填充</p><figure><img src="https://gitee.com/eddie-lucas/images/raw/master/img/创建bean的主要过程.png" alt="" tabindex="0" loading="lazy"><figcaption></figcaption></figure><p>之后就是初始化阶段，首先，对象填充属性的过程，通过<code>populateBean()</code>方法来给对象填充属性，填充完属性之后，会调用<code>initializeBean()</code>方法，在这个方法中，主要有4个步骤：</p><ol><li>调用aware接口的方法</li><li>调用beanPostProcessor的前置增强方法</li><li>调用init方法</li><li>调用beanPostProcessor的后置增强方法</li></ol><div class="language-java line-numbers-mode" data-ext="java"><pre class="language-java"><code><span class="token keyword">protected</span> <span class="token class-name">Object</span> <span class="token function">initializeBean</span><span class="token punctuation">(</span><span class="token keyword">final</span> <span class="token class-name">String</span> beanName<span class="token punctuation">,</span> <span class="token keyword">final</span> <span class="token class-name">Object</span> bean<span class="token punctuation">,</span> <span class="token class-name">RootBeanDefinition</span> mbd<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name">System</span><span class="token punctuation">.</span><span class="token function">getSecurityManager</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">AccessController</span><span class="token punctuation">.</span><span class="token function">doPrivileged</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">PrivilegedAction</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Object</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token annotation punctuation">@Override</span>
            <span class="token keyword">public</span> <span class="token class-name">Object</span> <span class="token function">run</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                <span class="token function">invokeAwareMethods</span><span class="token punctuation">(</span>beanName<span class="token punctuation">,</span> bean<span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token function">getAccessControlContext</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">else</span> <span class="token punctuation">{</span>
        <span class="token comment">//调用aware接口的方法</span>
        <span class="token function">invokeAwareMethods</span><span class="token punctuation">(</span>beanName<span class="token punctuation">,</span> bean<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token class-name">Object</span> wrappedBean <span class="token operator">=</span> bean<span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>mbd <span class="token operator">==</span> <span class="token keyword">null</span> <span class="token operator">||</span> <span class="token operator">!</span>mbd<span class="token punctuation">.</span><span class="token function">isSynthetic</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">//前置增强</span>
        wrappedBean <span class="token operator">=</span> <span class="token function">applyBeanPostProcessorsBeforeInitialization</span><span class="token punctuation">(</span>wrappedBean<span class="token punctuation">,</span> beanName<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">try</span> <span class="token punctuation">{</span>
        <span class="token comment">//init方法</span>
        <span class="token function">invokeInitMethods</span><span class="token punctuation">(</span>beanName<span class="token punctuation">,</span> wrappedBean<span class="token punctuation">,</span> mbd<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Throwable</span> ex<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">BeanCreationException</span><span class="token punctuation">(</span>
            <span class="token punctuation">(</span>mbd <span class="token operator">!=</span> <span class="token keyword">null</span> <span class="token operator">?</span> mbd<span class="token punctuation">.</span><span class="token function">getResourceDescription</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
            beanName<span class="token punctuation">,</span> <span class="token string">&quot;Invocation of init method failed&quot;</span><span class="token punctuation">,</span> ex<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">if</span> <span class="token punctuation">(</span>mbd <span class="token operator">==</span> <span class="token keyword">null</span> <span class="token operator">||</span> <span class="token operator">!</span>mbd<span class="token punctuation">.</span><span class="token function">isSynthetic</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">//后置增强</span>
        wrappedBean <span class="token operator">=</span> <span class="token function">applyBeanPostProcessorsAfterInitialization</span><span class="token punctuation">(</span>wrappedBean<span class="token punctuation">,</span> beanName<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">return</span> wrappedBean<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>上面的第2步和第4步，就是我们通常说的AOP，对于AOP，将在其他文章进行介绍</p><h2 id="总结" tabindex="-1"><a class="header-anchor" href="#总结" aria-hidden="true">#</a> 总结</h2><p>Spring可以看作是一个容器，用来装我们需要的对象，它有一个比较重要的概念是IOC，即控制反转，将对象的控制权交给Spring，由Spring来创建对象。</p><p>容器和对象的创建流程主要分为以下几个步骤：</p><ol><li><p>先创建容器，即BeanFactory</p></li><li><p>通过BeanDefinitionReader读取解析各种类型的配置文件，从中解析bean的定义信息，封装成BeanDefinition</p></li><li><p>调用执行BeanFacoryPostProcessor</p></li><li><p>做一些准备工作：注册beanPostProcessor，准备监听器等</p></li><li><p>通过反射实例化对象</p></li><li><p>初始化对象：populateBean()，initializeBean()</p></li><li><p>获取到完整的对象</p><figure><img src="https://gitee.com/eddie-lucas/images/raw/master/img/Spring对象创建过程1.png" alt="Spring中对象创建流程图" tabindex="0" loading="lazy"><figcaption>Spring中对象创建流程图</figcaption></figure></li></ol></div><!--[--><!----><!--]--><footer class="page-meta"><div class="meta-item edit-link"><a href="https://github.com/eddie-lucas/edit/main/src/backend/spring/Spring4.3.x源码阅读.md" rel="noopener noreferrer" target="_blank" aria-label="编辑此页" class="nav-link label"><!--[--><svg xmlns="http://www.w3.org/2000/svg" class="icon edit-icon" viewBox="0 0 1024 1024" fill="currentColor" aria-label="edit icon"><path d="M430.818 653.65a60.46 60.46 0 0 1-50.96-93.281l71.69-114.012 7.773-10.365L816.038 80.138A60.46 60.46 0 0 1 859.225 62a60.46 60.46 0 0 1 43.186 18.138l43.186 43.186a60.46 60.46 0 0 1 0 86.373L588.879 565.55l-8.637 8.637-117.466 68.234a60.46 60.46 0 0 1-31.958 11.229z"></path><path d="M728.802 962H252.891A190.883 190.883 0 0 1 62.008 771.98V296.934a190.883 190.883 0 0 1 190.883-192.61h267.754a60.46 60.46 0 0 1 0 120.92H252.891a69.962 69.962 0 0 0-69.098 69.099V771.98a69.962 69.962 0 0 0 69.098 69.098h475.911A69.962 69.962 0 0 0 797.9 771.98V503.363a60.46 60.46 0 1 1 120.922 0V771.98A190.883 190.883 0 0 1 728.802 962z"></path></svg><!--]-->编辑此页<span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span><!----></a></div><div class="meta-item git-info"><div class="update-time"><span class="label">上次编辑于: </span><!----></div><div class="contributors"><span class="label">贡献者: </span><!--[--><!--[--><span class="contributor" title="email: 761404955@qq.com">Lucas</span><!--]--><!--]--></div></div></footer><nav class="vp-page-nav"><!----><a aria-label="过滤器和拦截器的区别" class="vp-link nav-link next nav-link next" href="/backend/spring/%E8%BF%87%E6%BB%A4%E5%99%A8%E5%92%8C%E6%8B%A6%E6%88%AA%E5%99%A8%E7%9A%84%E5%8C%BA%E5%88%AB.html"><div class="hint">下一页<span class="arrow end"></span></div><div class="link">过滤器和拦截器的区别<!----></div></a></nav><div id="comment" class="giscus-wrapper input-top" style="display:none;"><div class="loading-icon-wrapper" style="display:flex;align-items:center;justify-content:center;height:96px"><svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" preserveAspectRatio="xMidYMid" viewBox="25 25 50 50"><animateTransform attributeName="transform" type="rotate" dur="2s" keyTimes="0;1" repeatCount="indefinite" values="0;360"></animateTransform><circle cx="50" cy="50" r="20" fill="none" stroke="currentColor" stroke-width="4" stroke-linecap="round"><animate attributeName="stroke-dasharray" dur="1.5s" keyTimes="0;0.5;1" repeatCount="indefinite" values="1,200;90,200;1,200"></animate><animate attributeName="stroke-dashoffset" dur="1.5s" keyTimes="0;0.5;1" repeatCount="indefinite" values="0;-35px;-125px"></animate></circle></svg></div></div><!--[--><!----><!--]--><!--]--></main><!--]--><footer class="vp-footer-wrapper"><div class="vp-footer">记录，分享自己的学习过程.....</div><div class="vp-copyright">Copyright © 2025 小刘Learning</div></footer></div><!--]--><!--]--><!----><!----><!--]--></div>
    <script type="module" src="/assets/app-d83e1369.js" defer></script>
  </body>
</html>
